package com.hungry.hfw.dao;

import java.net.URL;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataAccessResourceFailureException;
import org.springframework.dao.DataRetrievalFailureException;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.jdbc.support.KeyHolder;

public class SimpleCoreDao implements CoreDao{
	private JdbcTemplate jdbcTemplate;
	private HungrySimpleRowMapper  hungrySimpleRowMapper;
	private String hungryQueryFile;
	private static Map<String, ApplicationContext> queryRepository = new HashMap<String, ApplicationContext>();
	private CustomQuery queryServiceFile;

	private void loadRepository(String queryFile, String queryName) {
		if (queryRepository.get(queryFile) == null) {
			URL path = Thread.currentThread().getContextClassLoader().getResource("resources/"+ queryFile);
			System.out.println(path.toString());
			try {
				queryRepository.put(queryFile, new FileSystemXmlApplicationContext(path.toString()));
			} catch (Exception e) {
				throw new DataRetrievalFailureException("Error Loading queryRepository... I can try later" + queryName, e);
			}
		}
	}
	
	public SimpleCoreDao() {
		setHungrySimpleRowMapper(new HungrySimpleRowMapper());
	}
	public JdbcTemplate getJdbcTemplate() {
		System.out.println(this.jdbcTemplate);
		return jdbcTemplate;
	}

	public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
		System.out.println("inside");
		this.jdbcTemplate = jdbcTemplate;
		System.out.println(jdbcTemplate);
	}




	@SuppressWarnings("unchecked")
	@Override
	public  Object getUniqueResult(Object o,CustomQuery query) throws Throwable {
		List<BaseEntity> result = get(o,query);
		if(result!=null && result.size()>0) {
			return result.get(0);
		}
		return null;
	}
	
	

	@Override
	public Object insert(Object o) throws Exception {
		ReflectionHolder rf = new ReflectionHolder();
		StringBuilder query = null;
			query = rf.getCompleteEntity(o);
			Object[] valueMap = rf.getValueArray();
			
			HungryStatementCreator hsc = new HungryStatementCreator();
			hsc.setQuery(query.toString());
			hsc.setValues(valueMap);
			if(rf.getAutoGenKey()!=null) {
				KeyHolder keyHolder = new GeneratedKeyHolder();
				this.jdbcTemplate.update(hsc,keyHolder);
				BeanWrapper beanWrapper = new BeanWrapperImpl(o);
				beanWrapper.setPropertyValue(rf.getAutoGenKey(), keyHolder.getKey());
				return beanWrapper.getWrappedInstance();
			} else {
				this.jdbcTemplate.update(hsc);
				return o;
			}

	}
	
	@Override
	public int update(Object o, CustomQuery updateQueryName) throws Throwable {
		int updateResult = 0;
		try {
			if (hungryQueryFile == null || hungryQueryFile.isEmpty()) {
				throw new HungryDAOException(
						HungryDAOException.QUERY_NAME_NOT_AVAILABLE);
			}
			
				loadRepository(hungryQueryFile, updateQueryName.getQueryName());
				SimpleQuery sq = (SimpleQuery) queryRepository.get(hungryQueryFile).getBean(updateQueryName.getQueryName());
				String query = sq.getQuery();
				HungryStatementCreator hsc = new HungryStatementCreator();
				hsc.setQuery(query);
				hsc.setValues(updateQueryName.getWhereList());
				hsc.setClassName(o.getClass());
				
				getHungrySimpleRowMapper().setCls(o.getClass());
				if(checkForUpdate(hsc,updateQueryName,query) >= 1) {
					hsc = new HungryStatementCreator();
					hsc.setQuery(query);
					hsc.setValues(updateQueryName.getWhereList());
					hsc.setClassName(o.getClass());
					hsc.setValues(updateQueryName.getValueList());
					updateResult =  this.jdbcTemplate.update(hsc);
					
				} else {
					System.out.println("Notavailable");
					throw new HungryDataCriticalException(HungryDataCriticalException.DATA_NOT_AVAILABLE);
				}
				
		} catch(HungryDataCriticalException e) {
			throw e;
		} catch (DataRetrievalFailureException e) {
			throw new HungryDAOException(HungryDAOException.HUNGRY_RETRIEVAL_FAILURE, e);

		} catch (DataAccessResourceFailureException e) {
			throw new HungryDAOException(HungryDAOException.DB_UNAVAILABLE, e);

		} catch (DataAccessException e) {
			throw new HungryDAOException(HungryDAOException.HUNGRY_INTERNAL, e);
		}
		return updateResult;
		
		
		
	}
	
	
	@SuppressWarnings("unchecked")
	private Integer checkForUpdate(HungryStatementCreator hsc, CustomQuery updateQueryName, String query) throws Throwable {
		Integer result = 0;
		try {
			query = query != null ? query.toUpperCase() : null;
			String whereClause = null;
			String tableName = null;
			if (query != null && query.contains("UPDATE")
					&& query.contains("SET") && query.contains("WHERE")) {
				whereClause = query.substring(query.indexOf("WHERE"));
				String str = query.substring(0, query.indexOf("SET"));
				tableName = str.replaceFirst("UPDATE", "");
			}
			String whereQuery = "SELECT COUNT(1) FROM " + tableName + " " + whereClause;
			System.out.println("Query - " + whereQuery);
			hsc.setQuery(whereQuery);
			hsc.setValues(updateQueryName.getWhereList());

			result = this.jdbcTemplate.query(hsc,new BeanPropertyRowMapper(hsc.getClass())).size();
			System.out.println("result - " + result);
		} catch (DataRetrievalFailureException e) {
			throw new HungryDAOException(
					HungryDAOException.HUNGRY_RETRIEVAL_FAILURE, e);

		} catch (DataAccessResourceFailureException e) {
			throw new HungryDAOException(HungryDAOException.DB_UNAVAILABLE, e);

		} catch (DataAccessException e) {
			throw new HungryDAOException(HungryDAOException.HUNGRY_INTERNAL, e);
		}
		return result;
	}
	
	public static void main(String[] args) {
		String query = "Update updatejijoupdate set name=?,love=?,rainu=? where id=?";
		query = query.toUpperCase();
		String str = query.substring(0,query.indexOf("SET"));
		System.out.println(str);
//		String tableName = str.substring(0,str.indexOf("SET"));
//		System.out.println(tableName);
		String tableName = str.replaceFirst("UPDATE", "");
		System.out.println(tableName.trim());
	}

	public void setHungrySimpleRowMapper(HungrySimpleRowMapper hungrySimpleRowMapper) {
		this.hungrySimpleRowMapper = hungrySimpleRowMapper;
	}

	public HungrySimpleRowMapper getHungrySimpleRowMapper() {
		return hungrySimpleRowMapper;
	}
	public void setQueryServiceFile(CustomQuery queryServiceFile) {
		this.queryServiceFile = queryServiceFile;
	}
	public CustomQuery getQueryServiceFile() {
		return queryServiceFile;
	}
	@SuppressWarnings("unchecked")
	@Override
	public List<BaseEntity> get(Object o,CustomQuery customQuery) throws Throwable {
		List<BaseEntity> result = null;
		try {
			System.out.println(hungryQueryFile);
			if (hungryQueryFile == null || hungryQueryFile.isEmpty()) {
				throw new HungryDAOException(HungryDAOException.QUERY_NAME_NOT_AVAILABLE);
			}
			loadRepository(hungryQueryFile, customQuery.getQueryName());
			SimpleQuery sq = (SimpleQuery) queryRepository.get(hungryQueryFile).getBean(customQuery.getQueryName());
			String query = sq.getQuery();
			HungryStatementCreator hsc = new HungryStatementCreator();
			hungrySimpleRowMapper.setCls(o.getClass());
			hsc.setQuery(query);
			hsc.setValues(customQuery.getValueList());
			System.out.println(query);
			System.out.println(getJdbcTemplate());
			result = (List<BaseEntity>)this.jdbcTemplate.query(hsc,  new BeanPropertyRowMapper(o.getClass()));
		} catch (DataRetrievalFailureException e) {
			throw new HungryDAOException(
					HungryDAOException.HUNGRY_RETRIEVAL_FAILURE, e);

		} catch (DataAccessResourceFailureException e) {
			throw new HungryDAOException(HungryDAOException.DB_UNAVAILABLE, e);

		} catch (DataAccessException e) {
			throw new HungryDAOException(HungryDAOException.HUNGRY_INTERNAL, e);
		}
		
		return result;
	}
	public String getHungryQueryFile() {
		return hungryQueryFile;
	}
	public void setHungryQueryFile(String hungryQueryFile) {
		this.hungryQueryFile = hungryQueryFile;
	}

	@Override
	public int deleteEntity(BaseEntity be, CustomQuery deleteQuery) throws Throwable {
			int result = 0;
		try {
			System.out.println(hungryQueryFile);
			if (hungryQueryFile == null || hungryQueryFile.isEmpty()) {
				throw new HungryDAOException(HungryDAOException.QUERY_NAME_NOT_AVAILABLE);
			}
			loadRepository(hungryQueryFile, deleteQuery.getQueryName());
			SimpleQuery sq = (SimpleQuery) queryRepository.get(hungryQueryFile).getBean(deleteQuery.getQueryName());
			String query = sq.getQuery();
			HungryStatementCreator hsc = new HungryStatementCreator();
			hungrySimpleRowMapper.setCls(be.getClass());
			hsc.setQuery(query);
			hsc.setValues(deleteQuery.getValueList());
			System.out.println(query);
			System.out.println(getJdbcTemplate());
			result = this.jdbcTemplate.update(hsc);
		} catch (DataRetrievalFailureException e) {
			throw new HungryDAOException(HungryDAOException.HUNGRY_RETRIEVAL_FAILURE, e);

		} catch (DataAccessResourceFailureException e) {
			throw new HungryDAOException(HungryDAOException.DB_UNAVAILABLE, e);

		} catch (DataAccessException e) {
			throw new HungryDAOException(HungryDAOException.HUNGRY_INTERNAL, e);
		}
		
		return result;
	}

}
